package core.util;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.log4j.Logger;

/**
 * @author songduk park
 * 
 */
public abstract class AbstractDao {

	protected SqlSessionFactory sessionFactory;

	Logger logger;

	static final int WARNNING_MAXIMUM_TIME = 60000;

	private void log(String id, StopWatch watch) {
		logger.debug("db: " + id + " " + watch.end() + "ms");
		if (watch.end() > WARNNING_MAXIMUM_TIME)
			logger.info("WARNNING WARNNING - SLOW DB");
	}

	public StringHashMap createMap() {
		return new StringHashMap();
	}

	public AbstractDao(SqlSessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
		this.logger = Logger.getLogger(this.getClass());
	}

	public AbstractDao(AbstractDao abstractDao) {
		this(abstractDao.sessionFactory);
	}

	public void select(String sqlId, Map<String, Object> map,
			AbstractResultHandler handler) {
		StopWatch watch = new StopWatch();
		SqlSession session = sessionFactory.openSession();

		System.out.println("handler=" + handler.getClass());
		try {
			handler.doSomethingBefore();
			session.select(sqlId, map, handler);
			session.commit();
			handler.doSomethingAfter();

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			session.close();
		}

		log(sqlId, watch);
	}

	public void select(String sqlId, Object parameter,
			ResultHandler resultHandler) {
		StopWatch watch = new StopWatch();
		SqlSession session = sessionFactory.openSession();
		try {
			session.select(sqlId, parameter, resultHandler);
			session.commit();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			session.close();
		}

		log(sqlId, watch);
	}

	protected SqlSession openSession() {
		return sessionFactory.openSession();
	}

	public List getList(String sqlId, Map<String, Object> map) {
		StopWatch watch = new StopWatch();
		List list = null;

		SqlSession session = sessionFactory.openSession();
		try {
			list = session.selectList(sqlId, map);
			session.commit();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			session.close();
		}

		log(sqlId, watch);
		return list;
	}

	public List getList(String sqlId, Object entity) {
		StopWatch watch = new StopWatch();
		List list = null;

		SqlSession session = sessionFactory.openSession();
		try {
			list = session.selectList(sqlId, entity);
			session.commit();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			session.close();
		}

		log(sqlId, watch);
		return list;
	}

	public List getList(String sqlId) {
		StopWatch watch = new StopWatch();
		List list = null;

		SqlSession session = sessionFactory.openSession();
		try {
			list = session.selectList(sqlId);
			session.commit();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			session.close();
		}

		log(sqlId, watch);
		return list;
	}

	public Object getObject(String sqlId, Map<String, Object> map) {
		StopWatch watch = new StopWatch();
		Object object = null;

		System.out.println("sql=" + sqlId);
		SqlSession session = sessionFactory.openSession();
		try {
			object = session.selectOne(sqlId, map);
			session.commit();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			session.close();
		}

		log(sqlId, watch);
		return object;
	}

	public Object getObject(String sqlId, Object entity) {
		StopWatch watch = new StopWatch();
		Object object = null;

		SqlSession session = sessionFactory.openSession();
		try {
			object = session.selectOne(sqlId, entity);
			session.commit();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			session.close();
		}

		log(sqlId, watch);
		return object;
	}

	public Object getObject(String sqlId) {
		StopWatch watch = new StopWatch();
		Object object = null;

		SqlSession session = sessionFactory.openSession();
		try {
			object = session.selectOne(sqlId);
			session.commit();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			session.close();
		}

		log(sqlId, watch);
		return object;
	}

	public int update(String sqlId, Object entity) {
		StopWatch watch = new StopWatch();
		int result = 0;
		SqlSession session = sessionFactory.openSession();
		try {
			result = session.update(sqlId, entity);
			session.commit();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			session.close();
		}

		log(sqlId, watch);
		return result;
	}

	public int update(String sqlId, Map<String, Object> map) {
		StopWatch watch = new StopWatch();
		int result = 0;
		SqlSession session = sessionFactory.openSession();
		try {
			result = session.update(sqlId, map);
			session.commit();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			session.close();
		}

		log(sqlId, watch);
		return result;
	}

	public int update(String sqlId) {
		StopWatch watch = new StopWatch();
		int result = 0;
		SqlSession session = sessionFactory.openSession();
		try {
			result = session.update(sqlId);
			session.commit();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			session.close();
		}

		log(sqlId, watch);
		return result;
	}

	public int delete(String sqlId) {
		StopWatch watch = new StopWatch();
		int result = 0;
		SqlSession session = sessionFactory.openSession();
		try {
			result = session.delete(sqlId);
			session.commit();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			session.close();
		}

		log(sqlId, watch);
		return result;
	}

	public int delete(String sqlId, Map<String, Object> map) {
		StopWatch watch = new StopWatch();
		int result = 0;
		SqlSession session = sessionFactory.openSession();
		try {
			result = session.delete(sqlId, map);
			session.commit();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			session.close();
		}

		log(sqlId, watch);
		return result;
	}

	public int delete(String sqlId, Object entity) {
		StopWatch watch = new StopWatch();
		int result = 0;
		SqlSession session = sessionFactory.openSession();
		try {
			result = session.delete(sqlId, entity);
			session.commit();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			session.close();
		}

		log(sqlId, watch);
		return result;
	}

	public int insert(String sqlId, Map<String, Object> map) {
		StopWatch watch = new StopWatch();
		int result = 0;
		SqlSession session = sessionFactory.openSession();
		try {
			result = session.insert(sqlId, map);
			session.commit();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			session.close();
		}

		log(sqlId, watch);
		return result;
	}

	public int insert(String sqlId, Object entity) {
		StopWatch watch = new StopWatch();
		int result = 0;
		SqlSession session = sessionFactory.openSession();
		try {
			result = session.insert(sqlId, entity);
			session.commit();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			session.close();
		}

		log(sqlId, watch);
		return result;
	}

	public void print(List<HashMap> list) {
		boolean first = true;
		for (HashMap row : list) {

			Set keys = row.keySet();
			if (first) {
				for (Object key : keys) {
					System.out.print(key + "\t");
				}
				System.out.println();
			}

			for (Object key : keys) {
				System.out.print(row.get(key) + "\t");
			}
			System.out.println();
		}
	}

	public void print(HashMap row) {
		Set keys = row.keySet();

		for (Object key : keys) {
			System.out.print(key + "\t");
		}
		System.out.println();

		for (Object key : keys) {
			System.out.print(row.get(key) + "\t");
		}
	}
}
